package soendtrs;

import helpers.d;
import soenudp.Command;
import soenudp.UDPException;
import soenudp.UDPHelper;
import soenudp.UDPMessage;

/**
 * @author Davis
 * Received thread to handle responses. 
 */
public class DTRSViewRecv extends Thread {
    Object RECV_LOCK;
    UDPHelper unicastSocket;
    final int PORT  = 30000; // Server port where others can reach me.
    String MTL_View = "";    // A String holding the view. Could be a 
    String TOR_View = "";    // Hash Map, Table, List, Dictionary...

    String torIpOfTheLeader = "127.0.0.1"; // Get's updated once a TOR replica reply to WHO_LEADS
    String mtlIpOfTheLeader = "127.0.0.1"; // Get's updated once a MTL replica reply to WHO_LEADS
    
    public DTRSViewRecv() {
        RECV_LOCK = new Object();
    }

    public void run() {
        unicastSocket = new UDPHelper();
        try {
            unicastSocket.startUnicastServer("THE_VIEW_RECEIVER", PORT);
            
            UDPMessage request = new UDPMessage();
            
            while ( (request = unicastSocket.getMessage()) != null ) {
                processRequest(request);
                if (interrupted()) {
                    d.out("Interrupted DTRSViewRecv Thread");
                    break;
                }
            }
            unicastSocket.stopUnicast();
        } catch (UDPException e) {
            e.printStackTrace();
        }
    }

    private void processRequest(UDPMessage request) {
        int fromPort = request.recv_from_port;
        String fromIP = request.recv_from_ip;
        String textval = request.op_text; //in case you need more...
        Command command = request.command;

        switch (command) {
        case PONG:
            // d.out("PONG From IP: " + fromIP + " PORT: " + fromPort + " NodeID: " + nodeID);
            synchronized (RECV_LOCK) {
                if (textval.startsWith("MTL"))
                    MTL_View += textval + ":" + fromIP + ":" + fromPort + "\n";
                else
                    TOR_View += textval + ":" + fromIP + ":" + fromPort + "\n";
            }
            break;

        case WHO_LEADS:
            String[] typeAndIP = textval.split("--");
            synchronized (RECV_LOCK) {
                if (typeAndIP[0].equals("MTL")) {
                    mtlIpOfTheLeader = typeAndIP[1];
                } else {
                    torIpOfTheLeader = typeAndIP[1];
                }
            }
            
            break;

        case OTHER_LEAD: // Use by leaders to know IP Address of the other leader.
          String ip_address = (textval.equals("MTL")) ? torIpOfTheLeader : mtlIpOfTheLeader;
          UDPMessage deOder = new UDPMessage("", "", Command.OTHER_LEAD, 0,  0, ip_address); 
          unicastSocket.sendToNode(request.recv_from_ip, request.recv_from_port, deOder);
          
          break;
          
        case WAKEUP: // Reponse we got back from a WAKEUP command.
          String newAwakenNode = textval;
          d.out("New NodeID in the group is: " + newAwakenNode + "\n");
          
          break;
          
        default: // Should not really end up here...
            d.out("Un-implemented command\n" + request);
            break;

        }
    }

    public String getTORView() {
        synchronized (RECV_LOCK) {
            return this.TOR_View;
        }
    }

    public String getMTLView() {
        synchronized (RECV_LOCK) {
            return this.MTL_View;
        }
    }

    public void clearAllViews() {
        synchronized (RECV_LOCK) {
            this.MTL_View = "";
            this.TOR_View = "";
        }
    }

    public String getMTLLeader() {
        synchronized (RECV_LOCK) {
            return mtlIpOfTheLeader;
        }
    }

    public String getTORLeader() {
        synchronized (RECV_LOCK) {
            return torIpOfTheLeader;
        } 
    }
}
